iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 17
0
Modern Web

從巨人的 Tip 看 Angular系列 第 17

[Day 17] 透過 directive 來動態插入 Component!

  • 分享至 

  • xImage
  •  

好的!重新回歸到「從巨人的 Tip 看 Angular」系列,今天要分享的 Tip 是透過 ComponentFactoryResolver 來建立一個能夠動態將 component 實體化並 append 到 DOM 的載入器 ?


直接看結果

01

↑ Image 1

貓咪可愛!

關於程式碼的部分

今天的 Tip 會透過一個 directive 來實作,並稱他叫做 AnchorDirective,因為在我的範例中,這個 directive 就是扮演著「錨點」的角色,提供插入 component 元素的定位點功能。

另外新增了 4 個 component,分別是:

  1. StyleComponent:做為基底類別,所有 @Input property 都寫在這個類別內,但不提供 template。
  2. StyleAComponent:繼承 StyleComponent,直接取得 @Input property,提供第一種版型的 template。
  3. StyleBComponent:繼承 StyleComponent,直接取得 @Input property,提供第二種版型的 template。
  4. StyleCCompoennt:繼承 StyleComponent,直接取得 @Input property,提供第三種版型的 template。
@Directive({
  selector: '[anchor]',
})
export class AnchorDirective {
  constructor(
    private viewContainerRef: ViewContainerRef,
    private cmpFactoryResolver: ComponentFactoryResolver,
    private injector: Injector
  ) {}

  // ... 下接 Block 2
}

↑ Block 1

今天實作的重點有兩個,第一個是 ViewContainerRef、第二個則是 ComponentFactoryResolver

ViewContainerRef 這個類別的功能其實就如同它的名稱一樣,可以包含一個或是多個 view,就如同容器一般。而透過 createComponent 這個方法,開發者可以在容器上建立出新的 component。當在 directive 上使用 DI 取得 ViewContainerRef 的物件實體時,它所提供的 view container 的會是 directive host element 的 view container。

ComponentFactoryReolver 則是負責解析出 component 的工廠方法,這個工廠方法可以提供給 ViewContainerRef,用於 render component。

loadComponent(componentClass: Type<StyleComponent>, data: StyleData): void {
  this.viewContainerRef.clear();

  const cmpFactory = this.cmpFactoryResolver
					.resolveComponentFactory<StyleComponent>(componentClass);
  const cmp = this.viewContainerRef
					.createComponent<StyleComponent>(cmpFactory, 0, this.injector);

  Object.entries(data).forEach(([key, value]) => {
    cmp.instance[key] = value;
  });
}

↑ Block 2

Block 2 的程式碼就是所有的實作內容。

首先只要呼叫了這個方法,就會先清空 view container 的所有元素,因為我的功能需求是替換掉現在 view container 的內容,而不是不斷新增新的 component 到 container 內。

清空內容之後,再來會透過 ComponentFactoryResolver 的 resolveComponentFactory 來解析 component 的工廠方法,這部分我們有機會再提,目前只需要知道在呼叫這個方法之後,Angular 會產生一個物件,裡面會包含這個 component 的 definition、type、ngModule、selector 等 render 時所需要的所有資訊。

接著就是透過 ViewContainerRef 的 createComponent 方法來 render 一個完整的 component 到 view container 內。

最後的一個步驟則是處理 component 的 property。

接著就可以在 template 內使用囉:

<button
  mat-raised-button
  color="accent"
  *ngFor="let cmpObj of cmpList"
  (click)="changeComponent(cmpObj.cmp)"
>
  Style {{ cmpObj.name }}
</button>
<ng-template anchor></ng-template>

↑ Block 3

以上就是今天要介紹的 Tip,透過 ViewContainerRef 與 ComponentFactoryResolver 就可以達成動態插入 component 的功能囉 ?

中秋連假第二天 ?

以下按照入團順序列出我們團隊夥伴的系列文章!

請自由參閱 ?


上一篇
[Day 16] Not a Tip but a Trick!使用其他符號來做 interpolation 吧
下一篇
[Day 18] 寫了 ng-template 卻在渲染後只留下註解!關於 HTML tag 不見的秘密
系列文
從巨人的 Tip 看 Angular30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言